﻿// <copyright file="RGB.cs" company="BerlinSoft">
// Copyright (c) 2009 All Right Reserved
// </copyright>
// <author>Wernfried Schwenkner</author>
// <email>wernfried@schwenkner.de</email>
// <date>2009-10-21</date>
// <summary>
// Contains the class of a RGB color representation.
// </summary>

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;

namespace TimeTracker.Controls.ColorPickerForm.Base
{
	/// <summary>
	/// Structure to define RGB
	/// </summary>
	public struct RGB
	{
		/// <summary>
		/// Defines an empty object if type <see cref="RGB"/>.
		/// </summary>
		public static readonly RGB Empty = new RGB();

		/// <summary>
		/// Red component of the color
		/// </summary>
		private int red;

		/// <summary>
		/// Green component of the color
		/// </summary>
		private int green;

		/// <summary>
		/// Blue component of the color
		/// </summary>
		private int blue;

		/// <summary>
		/// Initializes a new instance of the <see cref="RGB"/> struct.
		/// </summary>
		/// <param name="r">red value of the color</param>
		/// <param name="g">green value of the color</param>
		/// <param name="b">blue value of the color</param>
		public RGB(int r, int g, int b)
		{
			red = (r > 255) ? 255 : ((r < 0) ? 0 : r);
			green = (g > 255) ? 255 : ((g < 0) ? 0 : g);
			blue = (b > 255) ? 255 : ((b < 0) ? 0 : b);
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="RGB"/> struct.
		/// </summary>
		/// <param name="color">The color.</param>
		public RGB(Color color)
		{
			red = color.R;
			green = color.G;
			blue = color.B;
		}

		/// <summary>
		/// Gets or sets red value
		/// </summary>
		public int Red
		{
			get { return red; }
			set { red = (value > 255) ? 255 : ((value < 0) ? 0 : value); }
		}

		/// <summary>
		/// Gets or sets green value.
		/// </summary>
		public int Green
		{
			get { return green; }
			set { green = (value > 255) ? 255 : ((value < 0) ? 0 : value); }
		}

		/// <summary>
		/// Gets or sets blue value.
		/// </summary>
		public int Blue
		{
			get { return blue; }
			set { blue = (value > 255) ? 255 : ((value < 0) ? 0 : value); }
		}

		/// <summary>
		/// Gets or sets the color
		/// </summary>
		public Color Color
		{
			get
			{
				return Color.FromArgb(red, green, blue);
			}

			set
			{
				red = value.R;
				green = value.G;
				blue = value.B;
			}
		}

		/// <summary>
		/// operator == to compare RGB colors
		/// </summary>
		/// <param name="rgb1">first value to be compared</param>
		/// <param name="rgb2">second value to be compared</param>
		/// <returns>true, if all components have the same value</returns>
		public static bool operator ==(RGB rgb1, RGB rgb2)
		{
			return
				rgb1.Red == rgb2.Red &&
				rgb1.Green == rgb2.Green &&
				rgb1.Blue == rgb2.Blue;
		}

		/// <summary>
		/// operator != to compare RGV colors
		/// </summary>
		/// <param name="rgb1">first value to be compared</param>
		/// <param name="rgb2">second value to be compared</param>
		/// <returns>true, if one component of both colors differ</returns>
		public static bool operator !=(RGB rgb1, RGB rgb2)
		{
			return
				rgb1.Red != rgb2.Red ||
				rgb1.Green != rgb2.Green ||
				rgb1.Blue != rgb2.Blue;
		}

		/// <summary>
		/// Converts color to HSL
		/// </summary>
		/// <param name="color">The color.</param>
		/// <returns>The HSL value of color.</returns>
		public static HSL ToHSL(Color color)
		{
			return ToHSL(color.R, color.G, color.B);
		}

		/// <summary>
		/// Converts RGB to HSL.
		/// </summary>
		/// <param name="red">Red value, must be in [0,255].</param>
		/// <param name="green">Green value, must be in [0,255].</param>
		/// <param name="blue">Blue value, must be in [0,255].</param>
		/// <returns>The HSL value.</returns>
		public static HSL ToHSL(int red, int green, int blue)
		{
			int hue = 0, saturation = 0, luminance = 0;

			int max = Math.Max(red, Math.Max(green, blue));
			int min = Math.Min(red, Math.Min(green, blue));

			// hue
			if (max == min)
			{
				hue = 0; // undefined
			}
			else if (max == red && green >= blue)
			{
				hue = 60 * (green - blue) / (max - min);
			}
			else if (max == red && green < blue)
			{
				hue = 60 * (green - blue) / (max - min) + 360;
			}
			else if (max == green)
			{
				hue = 60 * (blue - red) / (max - min) + 120;
			}
			else if (max == blue)
			{
				hue = 60 * (red - green) / (max - min) + 240;
			}

			// luminance
			luminance = (max + min) / 2;

			// saturation
			if (luminance == 0 || max == min)
			{
				saturation = 0;
			}
			else if (luminance < 128)
			{
				saturation = (max - min) * 255 / (max + min);
			}
			else
			{
				saturation = (max - min) * 255 / (512 - (max + min));
			}

			return new HSL(hue, saturation, luminance);
		}

		/// <summary>
		/// Converts the RGB representation into HSL one.
		/// </summary>
		/// <returns>The HSL representauon of the color</returns>
		public HSL ToHSL()
		{
			return ToHSL(red, green, blue);
		}

		/// <summary>
		/// Converts the RGB representation into Argb one with alpha transparence set to zero.
		/// </summary>
		/// <returns>The Argb representation of the color</returns>
		public int ToArgb()
		{
			return (red << 16) + (green << 8) + blue;
		}

		/// <summary>
		/// Compares if two instances of the class are equal
		/// </summary>
		/// <param name="other">the other instance to compare</param>
		/// <returns>true, if both instances have the same color</returns>
		public override bool Equals(object other)
		{
			if (other == null || GetType() != other.GetType())
			{
				return false;
			}

			return this == (RGB)other;
		}

		/// <summary>
		/// Calculates the hash code
		/// </summary>
		/// <returns>The hash code of the color</returns>
		public override int GetHashCode()
		{
			return Red.GetHashCode() ^ Green.GetHashCode() ^ Blue.GetHashCode();
		}
	}
}
